/******************************************************************************

Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, PHP, Ruby, 
C#, VB, Perl, Swift, Prolog, Javascript, Pascal, HTML, CSS, JS
Code, Compile, Run and Debug online from anywhere in world.

*******************************************************************************/
#include <stdio.h>
#include <iostream>
#include <map>

// 变量模板与成员变量模板
// 变量模板：Variable Template C++14新标准中引入的（一般放在.h头文件中）
// 使用感觉上，变量模板与函数模板有些类似，看起来像一个没有参数，但是有返回值的函数模板
// template<typename T>
// T g_myarr{};
// 这里的{}是一种对变量的初始化方式。（叫做0初始化），所谓的0初始化，就是对于数值型变量，就初始化为0
// 对于指针型变量，就初始化为nullptr，bool型变量就初始化为false
// 试想，对于这些变量，如果我们不对其进行初始化，那么在局部作用域中，这些变量将会是任意值

// 有3种方式都是0初始化方式《T表示一个类型》
// 1）T();      // int tmp1 = int();
// 2）T t = {}; // int tmp2 = {};
// 3）T {};     // int tmp3{};


// 变量模板的特化
// 变量模板的全特化
// 变量模板的特化版本
//     template<>
//     char g_myarr<double>{};
// 变量模板特化的时候，并不需要正在特化的类型（double）和这个变量模板的类型（char）保持一致

// 变量模板的偏特化

// 默认模板参数

// 非类型模板参数

// 变量模板的另一种形式

// 成员变量模板

// 别名模板与成员别名模板【Alias Template】
// 他是c++11新标准中引入的，引入的目的不单能简化书写，而且可以达到一些通过其他手段才能达到的效果

namespace _nmsp1
{
    // 变量模板的泛化版本
    template<typename T>
    T g_myarr{};
    // 或者写成下面这种，都不会出现语法错。但是下面这种写法一般只适合数值类型
    // T g_myarr = 0;
    
    // 变量模板的全特化版本
    // 变量模板特化的时候，并不需要正在特化的类型（double）和这个变量模板的类型（char）保持一致
    template<>
    char g_myarr<double>{};
    
    // 偏特化
    template<typename T>
    T g_myarr<T *>{120};
    // 变量模板的类型：T
    // 正在特化的类型：T* ,相当于范围缩小了
    // 这个和上面那个全特化不一样，这里要求正在特化的类型T*必须依赖于变量模板类型T
    // T g_myarr<double *>{120};    // 比如这种，double根本不依赖T，这样的偏特化就会编译报错
    
    void func()
    {
        // 变量模板使用的时候直接当成变量名来使用就可以
        g_myarr<float> = 14.65f;
        g_myarr<int> = 32; 
    
        std::cout << g_myarr<float> << std::endl;   // 14.65
        std::cout << g_myarr<int> << std::endl;     // 32
        
        char *p{}; // nullptr, NULL
        int q{};  // 0
        if (p==nullptr)
        {
            std::cout << "0初始化为nullptr" << std::endl;
            // 0初始化为nullptr
        }
        
        std::cout << q << std::endl;
        // 0
        
        // 零初始化的3总方式
        int tmp1 = int();
        int tmp2 = {};
        int tmp3{};
        
        std::cout << "-------------------变量模板全特化-----------------" << std::endl;
        g_myarr<double> = 't';
        // 这个使用的就是上面特化版本的g_myarr变量模板
        std::cout << g_myarr<double> << std::endl; // t
        
        std::cout << "-------------------变量模板偏特化-----------------" << std::endl;
        std::cout << g_myarr<int *> << std::endl; // 120    // 走偏特化版本
        std::cout << g_myarr<int> << std::endl; // 32      // 走泛化版本（上面进行过重新赋值）
    }
}

namespace _nmsp2
{
    // 变量模板的泛化版本
    // 默认模板参数
    template<typename T = int>
    T g_myarr;
    // 这里给不给初值都可以，看你自己实际需求
    
    
    
    void func()
    {
        g_myarr<int> = 120;
        std::cout << g_myarr<int> << std::endl; // 120
        // 既然我们的变量模板已经给了默认模板参数
        // 那么这里不给模板参数也是可以的,虽然<>里的类型可以省略，但是<>这个本身是不能少的
        std::cout << g_myarr<> << std::endl;    // 120 g_myarr<>等价于g_myarr<int>，他们是一个变量
        g_myarr<> = 99;
        std::cout << g_myarr<> << std::endl;    // 99
        
        
        
    }
}

namespace _nmsp3
{
    // 变量模板的泛化版本
    // 非类型模板参数
    template<typename T, int value>
    T g_myarr[value];
    // 前面变量模板类型参数用的是类型模板参数，后面用的是非类型模板参数
    
    
    
    void func()
    {
        for (int i = 0; i < 10; ++i)
        {
            g_myarr<int, 10>[i] = i;
            // 注意：中括号[]中的数字要小于等于这里的10，表示0-10之间，否者下标会越界
            // 只要代码中这种写法g_myarr<int, 10>一出现，就表示定义了g_myarr<int, 10>[i]
            // 大小为10的个元素的int类型的数组
        }
        
        for (int i = 0; i < 10; ++i)
        {
            std::cout << g_myarr<int, 10>[i] << std::endl;
            // 0
            // 1
            // 2
            // 3
            // 4
            // 5
            // 6
            // 7
            // 8
            // 9
        }
        
        
        
    }
}

namespace _nmsp4
{
    // 先创建一个类模板TC
    template<typename T>
    class TC
    {
    public:
        const static T value = {189};
        // 这里const也可以写成constexpr， 同时{}也可以不加
    };
    
    // 变量模板
    template<typename T>
    int g_myarr = TC<T>::value;
    // 注意该变量模板的写法，他和类模板TC在变量模板中共用一个变量类型
    
    
    void func()
    {
        std::cout << g_myarr<int> << std::endl; // 189  // g_myarr<int>相当于TC<int>::value
        g_myarr<int> = 100;
        std::cout << g_myarr<int> << std::endl; // 100
        std::cout << TC<int>::value << std::endl;   // 189
        // 注意这里：虽然改变了g_myarr<int>的值，但是并没有改变到TC<int>::value中的值
    }
}

namespace _nmsp5
{
    // 先创建一个类模板TC
    template<typename T>
    class TC
    {
    public:
        // 成员变量模板
        template<typename V>
        static V m_gti;  // 静态成员变量模板声明
    };
    
    // 定义静态成员变量模板
    template<typename T>
    template<typename V>
    V TC<T>::m_gti = 5;
    
    
    void func()
    {
        std::cout << TC<float>::m_gti<int> << std::endl;    // 5
        TC<float>::m_gti<int> = 1902;
        std::cout << TC<float>::m_gti<int> << std::endl;    // 1902
        
    }
}

namespace _nmsp6
{
    // 别名模板
    template<typename T>
    using str_map_t = std::map<std::string, T>;
    // 定义了这样一个别名模板str_map_t， 他是一个map，键值为string类型，值为T类型的值
    
    // 如果是放在类或者类模板中，别名模板一帮都是放在最上面，而且这个东西不需要public修饰
    template<typename T>
    class TC
    {
        // 成员别名模板
        template<typename U>
        using str_map_t = std::map<std::string, U>;
        
    public:
        str_map_t<int> m_intMap;
    };
    
    
    void func()
    {
        str_map_t<int> nmp1;
        nmp1.insert({"first", 120});
        nmp1.insert({"second", 210});
        nmp1.insert({"three", 4210});
        nmp1.insert({"four", 292});
        nmp1.insert({"five", 2320});
        
        // for(auto iter = nmp1.begin(); iter != nmp1.end(); ++iter)    // 直接auto也行
        for(str_map_t<int>::iterator iter = nmp1.begin(); iter != nmp1.end(); ++iter)
        {
            std::cout << iter->first << "-----" << iter->second << std::endl;
            // first-----120
            // five-----2320
            // four-----292
            // second-----210
            // three-----4210
        }
        
        
        // 成员别名模板
        TC<float> obj;
        obj.m_intMap.insert({"first", 120});
        obj.m_intMap.insert({"second", 210});
        obj.m_intMap.insert({"three", 4210});
        obj.m_intMap.insert({"four", 292});
        obj.m_intMap.insert({"five", 2320});
        
        for(str_map_t<int>::iterator it = obj.m_intMap.begin(); it != obj.m_intMap.end(); ++it)
        {
            std::cout << "键 = " << it->first << "，值 = " << it->second << std::endl;
            // 键 = first，值 = 120
            // 键 = five，值 = 2320
            // 键 = four，值 = 292
            // 键 = second，值 = 210
            // 键 = three，值 = 4210
        }
    }
}

int main()
{
    // _nmsp1::func();
    // _nmsp2::func();
    // _nmsp3::func();
    // _nmsp4::func();
    // _nmsp5::func();
    _nmsp6::func();

    return 0;
}
